package cn.xiaolang.function.test_map;

import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;

import org.apache.commons.lang3.time.DateUtils;

/**
 * 过期设定&LRU规则的map集合
 *
 * @param <K> key
 * @param <V> value
 * @author DeanKano
 * @date 2018年1月22日
 */
public class ExpireLruMap<K, V> {

    private int capacity;
    private Map<K, V> cache;
    private Map<K, Long> expireMonitor = new HashMap<>();// 过期监控
    private static final int DEFAULT_EXPIRED_MAX_SECOND = 30 * 60 * 1000;// 默认过期时间（S）

    ExpireLruMap(final int capacity) {
        this.capacity = capacity;
        // true 表示让 linkedHashMap 按照访问顺序来进行排序，最近访问的放在头部，最老访问的放在尾部
        this.cache = new LinkedHashMap<K, V>(capacity, 0.75f, true) {
            private static final long serialVersionUID = 1L;

            // 定义put后的移除规则，大于容量就删除eldest
            @Override
            protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
                return size() > capacity;
            }
        };
    }

    public void put(K key, V value) {
        cache.put(key, value);
    }

    public V get(Object key) {
        V v = cache.get(key);
        if (v == null) {
            expireMonitor.remove(key);
        } else {
            Long expiretime = expireMonitor.get(key);
            if (expiretime != null) {
                long curtime = System.currentTimeMillis();
                if (curtime > expiretime) {
                    expireMonitor.remove(key);
                    cache.remove(key);
                    return null;
                } else {
                    return v;
                }
            }
        }
        return v;
    }

    /**
     * 默认过期时间（s）
     */
    public void putExpire(K key, V value) {
        cache.put(key, value);
        expireMonitor.put(key, DateUtils.addSeconds(new Date(), DEFAULT_EXPIRED_MAX_SECOND).getTime());
    }

    /**
     * 设定过期时间（s）
     */
    public void putExpire(K key, V value, int expiredSeconds) {
        cache.put(key, value);
        expireMonitor.put(key, DateUtils.addSeconds(new Date(), expiredSeconds).getTime());
    }

    @Override
    public String toString() {
        return "LRUCache [capacity=" + capacity + ", cache=" + cache + "]";
    }

}
